package com.loongtech.bi.dao.impl;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.beanutils.BeanUtils;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.ResultSetExtractor;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Service;

import com.loongtech.bi.dao.CommonDao;

@Service("commonDao")
public class CommonDaoImpl implements CommonDao {
	private static final long serialVersionUID = 1L;

	private JdbcTemplate jdbcTemplate;

	public JdbcTemplate getJdbcTemplate() {
		return jdbcTemplate;
	}

	public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
		this.jdbcTemplate = jdbcTemplate;
	}

	private List<String> getColumnList(ResultSetMetaData rsmd) {
		int columnCount = 0;
		List<String> columnList = null;
		try {
			columnCount = rsmd.getColumnCount();
			if (columnCount > 0) {
				columnList = new ArrayList<String>();
				for (int i = 1; i <= columnCount; i++) {
					String columnname = rsmd.getColumnName(i);
					columnList.add(columnname.toLowerCase());
				}
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return columnList;
	}

	@Override
	public List<List<String>> queryListData(String sql, Object[] o) {
		List<List<String>> result = new ArrayList<List<String>>();
		List<Map<String, Object>> re = jdbcTemplate.queryForList(sql, o);
		for (Map<String, Object> m : re) {
			Set<String> ls = m.keySet();
			List<String> lsub = new ArrayList<String>();
			for (String ss : ls) {
				lsub.add(String.valueOf(m.get(ss)));
			}
			result.add(lsub);
		}
		return result;
	}

	@Override
	public <T> T queryObj(String sql, Object[] args, final Class<T> clazz) {
		return jdbcTemplate.query(sql, args, new ResultSetExtractor<T>() {
			@Override
			public T extractData(ResultSet rs) throws SQLException, DataAccessException {
				T result = null;
				if (rs.next()) {
					try {
						result = clazz.newInstance();
						BeanInfo beanInfo = Introspector.getBeanInfo(clazz);
						PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
						for (PropertyDescriptor pd : pds) {
							Method setMethod = pd.getWriteMethod();
							if (setMethod != null) {
								String propertyName = pd.getName();
								BeanUtils.setProperty(result, propertyName, rs.getObject(propertyName));
							}
						}
					} catch (Exception e) {
						throw new RuntimeException(e);
					}
				}
				return result;
			}
		});
	}

	@Override
	public int queryForInt(String sql, Object[] o) {
		return jdbcTemplate.queryForObject(sql, o, Integer.class);
	}

	@Override
	public <T> List<T> queryObjList(String sql, Object[] args, final Class<T> clazz) {
		return jdbcTemplate.query(sql, args, new RowMapper<T>() {
			@Override
			public T mapRow(ResultSet rs, int arg1) throws SQLException {
				T result = null;
				ResultSetMetaData rsmd = rs.getMetaData();
				List<String> columns = getColumnList(rsmd);
				try {
					result = clazz.newInstance();
					BeanInfo beanInfo = Introspector.getBeanInfo(clazz);
					PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
					for (PropertyDescriptor pd : pds) {
						Method setMethod = pd.getWriteMethod();
						if (setMethod != null) {
							String propertyName = pd.getName();
							if (columns.contains(propertyName.toLowerCase())) {
								BeanUtils.setProperty(result, propertyName, rs.getObject(propertyName));
							}
						}
					}
				} catch (Exception e) {
					throw new RuntimeException(e);
				}
				return result;
			}
		});
	}

	@Override
	public int addOrUpdate(String sql, Object[] o) {
		return jdbcTemplate.update(sql, o);
	}
}
